package org.cbyyx.tc.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.cbyyx.tc.common.LoginLocal;
import org.cbyyx.tc.enums.ErrorCode;
import org.cbyyx.tc.enums.OrderStatus;
import org.cbyyx.tc.exception.BusinessException;
import org.cbyyx.tc.exception.ThrowUtils;
import org.cbyyx.tc.mapper.OrdersMapper;
import org.cbyyx.tc.model.dto.orderRequest.OrderCreateRequest;
import org.cbyyx.tc.model.dto.orderRequest.OrderQueryRequest;
import org.cbyyx.tc.model.entity.Order;
import org.cbyyx.tc.model.entity.OrderItems;
import org.cbyyx.tc.model.entity.Products;
import org.cbyyx.tc.model.entity.User;
import org.cbyyx.tc.model.vo.orderResponse.OrderDetailVO;
import org.cbyyx.tc.model.vo.userResponse.UserVO;
import org.cbyyx.tc.service.OrderItemsService;
import org.cbyyx.tc.service.OrderService;
import org.cbyyx.tc.service.ProductsService;
import org.cbyyx.tc.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author Administrator
* @description 针对表【orders】的数据库操作Service实现
* @createDate 2025-04-21 15:41:21
*/
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrdersMapper, Order> implements OrderService {

    private final UserService userService;
    private final ProductsService productsService;
    private final OrderItemsService orderItemsService;
    private final Snowflake snowflake = new Snowflake();

    /**
     * 创建订单
     * @param request 包含商品信息和收货地址的请求
     * @return 订单编号
     */
    @Override
    @Transactional
    public OrderDetailVO createOrder(OrderCreateRequest request) {

        // 检查用户是否登录
        UserVO userVO = LoginLocal.getLoginUser();
        ThrowUtils.throwIf(userVO == null, ErrorCode.NOT_LOGIN_ERROR, "用户未登录");

        // 检查传入商品信息是否合法
        Map<Long, Integer> productQuantityMap = request.getProductQuantityMap();
        ThrowUtils.throwIf(productQuantityMap.isEmpty(), ErrorCode.PARAMS_ERROR, "商品信息为空");

        // 检查传入商品数量是否合法
        for (Map.Entry<Long, Integer> entry : productQuantityMap.entrySet()) {
            ThrowUtils.throwIf(entry.getKey() <= 0, ErrorCode.PARAMS_ERROR, "商品ID不合法");
            ThrowUtils.throwIf(entry.getValue() <= 0, ErrorCode.PARAMS_ERROR, "商品数量不合法");
        }

        // 批量查询商品信息
        List<Products> products = productsService.listByIds(new ArrayList<>(productQuantityMap.keySet()));
        ThrowUtils.throwIf(products.size() != productQuantityMap.size(), ErrorCode.PARAMS_ERROR, "商品不存在");


        // 1. 扣减库存
        // 实际扣减库存操作（保持原有逻辑）
        productQuantityMap.forEach((productId, quantity) ->
            ThrowUtils.throwIf(!productsService.decreaseStock(productId, quantity),ErrorCode.OPERATION_ERROR, "商品库存不足")
        );
        // 2. 计算总价
        Long userId = userVO.getId();
        long totalPrice = products.stream()
                .mapToLong(product -> 
                    product.getPrice() * productQuantityMap.get(product.getId())
                ).sum();
        // 3. 创建订单主表
        Order order = new Order();
        order.setId(snowflake.nextId());
        order.setUserId(userId);
        order.setTotalPrise(totalPrice);
        order.setStatus(OrderStatus.PENDING.getCode());
        order.setAddressId(request.getAddressId());

        // 保存订单主表
        while (this.getById(order.getId())!=null){
            order.setId(snowflake.nextId());
        }
        ThrowUtils.throwIf(!this.save(order),ErrorCode.SYSTEM_ERROR);

        // 4. 创建订单明细
        List<OrderItems> details = products.stream()
                .map(product -> OrderItems.builder()
                        .orderId(order.getId())
                        .productId(product.getId())
                        .quantity(productQuantityMap.get(product.getId()))
                        .price(product.getPrice())
                        .productName(product.getName())
                        .build()
                    )
                .collect(Collectors.toList());
        // 保存订单明细
        ThrowUtils.throwIf(!orderItemsService.saveBatch(details),ErrorCode.SYSTEM_ERROR);

        // 5. 返回订单详情
            OrderDetailVO vo = new OrderDetailVO();
            vo.setOrderId(order.getId());
            vo.setStatus(order.getStatus());
            vo.setTotalPrice(totalPrice);
            vo.setAddressId(request.getAddressId());
            vo.setOrderItems(details);
            // 设置其他字段
            return vo;
    }

    /**
     * 取消订单
     * @param orderId 订单ID
     * @return 是否取消成功
     */
    @Override
    @Transactional
    public Boolean cancelOrder(Long orderId) {
        // 1. 查询订单
        Order order = this.getById(orderId);
        ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");

        ThrowUtils.throwIf(order.getStatus() != OrderStatus.PENDING.getCode(),
                ErrorCode.OPERATION_ERROR, "订单状态不允许取消");
        
        // 2. 恢复库存
        List<OrderItems> items = orderItemsService.list(new QueryWrapper<OrderItems>().eq("orderId", orderId));
        items.forEach(item -> 
            ThrowUtils.throwIf(!productsService.increaseStock(item.getProductId(), item.getQuantity()),ErrorCode.OPERATION_ERROR, "库存恢复失败")
        );
        
        // 3. 更新订单状态
        order.setStatus(OrderStatus.CANCELLED.getCode());
        ThrowUtils.throwIf(!this.updateById(order),ErrorCode.SYSTEM_ERROR,"订单取消失败");
        return true;
    }

    /**
     * 获取订单详情
     * @param orderId 订单ID
     * @return 订单详情VO
     */
    @Override
    public OrderDetailVO getOrderDetail(Long orderId) {
        ThrowUtils.throwIf(orderId == null || orderId <= 0, ErrorCode.PARAMS_ERROR, "订单ID无效");
        // 1. 查询主订单
        Order order = this.getById(orderId);
        ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");
    
        // 2. 查询订单明细
        List<OrderItems> items = orderItemsService.list(new QueryWrapper<OrderItems>().eq("orderId", orderId));
        
        // 3. 组装VO
        OrderDetailVO vo = new OrderDetailVO();
        vo.setOrderId(order.getId());
        vo.setStatus(order.getStatus());
        vo.setTotalPrice(order.getTotalPrise());
        vo.setAddressId(order.getAddressId());
        vo.setOrderItems(items);
        return vo;
    }

    @Override
    public Page<OrderDetailVO> listOrders(OrderQueryRequest request) {
        // 1. 构建查询条件
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(request.getUserId() != null, Order::getUserId, request.getUserId())
               .eq(request.getStatus() != null, Order::getStatus, request.getStatus())
               .orderByDesc(Order::getCreateTime);
        
        // 2. 分页查询订单
        Page<Order> page = this.page(new Page<>(request.getCurrent(), request.getPageSize()), wrapper);
        
        // 3. 转换为VO
        return (Page<OrderDetailVO>) page.convert(order -> {
            OrderDetailVO vo = new OrderDetailVO();
            vo.setOrderId(order.getId());
            vo.setStatus(order.getStatus());
            vo.setTotalPrice(order.getTotalPrise());
            vo.setAddressId(order.getAddressId());
            return vo;
        });
    }

    /**
     * 支付订单
     * @param orderId 订单ID
     * @return 支付是否成功
     * @throws BusinessException 当订单不存在、用户未登录、订单不属于当前用户、余额不足或支付失败时抛出
     * @apiNote 1. 验证订单和用户信息
     *          2. 检查订单状态是否为待支付
     *          3. 扣除用户余额
     *          4. 更新订单状态为已支付
     */
    @Override
    @Transactional
    public Boolean payOrder(Long orderId) {
        // 1. 查询订单
        Order order = this.getById(orderId);
        ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");

        UserVO userVO = LoginLocal.getLoginUser();
        ThrowUtils.throwIf(userVO == null, ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        ThrowUtils.throwIf(!userVO.getId().equals(order.getUserId()),ErrorCode.OPERATION_ERROR, "订单不属于当前用户");

        boolean paid = userService.lambdaUpdate()
                .gt(User::getBalance, order.getTotalPrise())
                .setSql("balance = balance - " + order.getTotalPrise())
                .update();

        // 模拟支付
        if (!paid) {
            User user = userService.getById(userVO.getId());
            if (user.getBalance() < order.getTotalPrise())
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "余额不足");
            else
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "支付失败");
        }
        
        // 2. 检查订单状态是否为待支付
        ThrowUtils.throwIf(order.getStatus() != OrderStatus.PENDING.getCode(),
                ErrorCode.OPERATION_ERROR, "订单状态不允许支付");
        
        // 3. 更新订单状态为已支付
        order.setStatus(OrderStatus.PAID.getCode());
        ThrowUtils.throwIf(!this.updateById(order), ErrorCode.SYSTEM_ERROR, "订单支付失败");
        return true;
    }

    /**
     * 发货订单
     * @param orderId 订单ID
     * @return 发货是否成功
     * @throws BusinessException 当订单不存在或订单状态不允许发货时抛出
     * @apiNote 1. 验证订单存在
     *          2. 检查订单状态是否为已支付
     *          3. 更新订单状态为已发货
     */
    @Override
    @Transactional
    public Boolean deliverOrder(Long orderId) {
        // 1. 查询订单
        Order order = this.getById(orderId);
        ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");
        
        // 2. 检查订单状态是否为已支付
        ThrowUtils.throwIf(order.getStatus() != OrderStatus.PAID.getCode(),
                ErrorCode.OPERATION_ERROR, "订单状态不允许发货");
        
        // 3. 更新订单状态为已发货
        order.setStatus(OrderStatus.DELIVERED.getCode());
        ThrowUtils.throwIf(!this.updateById(order), ErrorCode.SYSTEM_ERROR, "订单发货失败");
        return true;
    }

    /**
     * 完成订单
     * @param orderId 订单ID
     * @return 完成是否成功
     * @throws BusinessException 当订单不存在、用户未登录、订单不属于当前用户或订单状态不允许完成时抛出
     * @apiNote 1. 验证订单和用户信息
     *          2. 检查订单状态是否为已发货
     *          3. 更新订单状态为已完成
     */
    @Override
    @Transactional
    public Boolean completeOrder(Long orderId) {
        // 1. 查询订单
        Order order = this.getById(orderId);
        ThrowUtils.throwIf(order == null, ErrorCode.NOT_FOUND_ERROR, "订单不存在");

        UserVO userVO = LoginLocal.getLoginUser();
        ThrowUtils.throwIf(userVO == null, ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        ThrowUtils.throwIf(!userVO.getId().equals(order.getUserId()),ErrorCode.OPERATION_ERROR, "订单不属于当前用户");

        // 2. 检查订单状态是否为已发货
        ThrowUtils.throwIf(order.getStatus() != OrderStatus.DELIVERED.getCode(),
                ErrorCode.OPERATION_ERROR, "订单状态不允许完成");
        
        // 3. 更新订单状态为已完成
        order.setStatus(OrderStatus.Completed.getCode());
        ThrowUtils.throwIf(!this.updateById(order), ErrorCode.SYSTEM_ERROR, "订单完成失败");
        return true;
    }
}